#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/device.h>
#include <linux/clk.h>

#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/sizes.h>
#include <asm/arch/hardware.h>


#define vicap_readw(addr, value)	(value = ( * ( volatile unsigned int * ) (addr)))
#define vicap_writew(addr, value)	(( * ( volatile unsigned int * )(addr)) = (value))


#define DEV_NAME	"vicap"
#define VICAP_NUM	2


#define VICAP_BASE	0x11380000
#define VICAP_SIZE	0x70000			/* 448K */

void __iomem * base;
#define IO_ADDRESS_VERIFY(x)	(base + ((x) - (VICAP_BASE)))

/* vicap register definition .*/	
#define VICAP_AXI_CFG(num)				IO_ADDRESS_VERIFY(VICAP_BASE + 0x0010 + (num * 0x100000))
#define VICAP_ISP_SEL(num)				IO_ADDRESS_VERIFY(VICAP_BASE + 0x0050 + (num * 0x100000))
#define VICAP_BUF_MODE(num)				IO_ADDRESS_VERIFY(VICAP_BASE + 0x0070 + (num * 0x100000))
#define VICAP_SLAVE_MODE_CFG(num)		IO_ADDRESS_VERIFY(VICAP_BASE + 0x00A0 + (num * 0x100000))
#define VICAP_INT(num)					IO_ADDRESS_VERIFY(VICAP_BASE + 0x00F0 + (num * 0x100000))
#define VICAP_INT_MASK(num)				IO_ADDRESS_VERIFY(VICAP_BASE + 0x00F8 + (num * 0x100000))
#define VICAP_PT_INTF_MOD(num)			IO_ADDRESS_VERIFY(VICAP_BASE + 0x0100 + (num * 0x100000))
#define VICAP_PT_OFFSET0(num)			IO_ADDRESS_VERIFY(VICAP_BASE + 0x0110 + (num * 0x100000))	/* test : Reset value is 0xfff00000 */

#define VICAP_REG_SUB_ADDR(num, reg)	IO_ADDRESS_VERIFY(VICAP_BASE + reg + (num * 0x100000))
 


typedef struct vicap_base
{
	unsigned long reg;
	unsigned long value;
}vicap_base;

static int test_read_default(void)
{
	unsigned int result = 0;

	vicap_readw(VICAP_PT_OFFSET0(0), result);
	printk("(0x%x = 0x%x)\n", VICAP_BASE + 0x0110, result);
}

static unsigned long read_vicap(unsigned long reg)
{
	unsigned long value;

	vlaue = readl(base + reg);
	printk("(0x%x = 0x%x\n", base + reg, value);

	return value;
}

static unsigned int write_vicap(vicap_base * vicap)
{
	printk("0x%x = 0x%x\n", base + vicap->reg, vicap->value);
	writel(vicap->value, base + vicap->reg);

	return 0;
}

static int vicap_open(struct inode * inode, struct file * file)
{
    return 0;
}
static int vicap_close(struct inode * inode, struct file * file)
{
    return 0;
}

static long vicap_ioctl(struct file * filp, unsigned int cmd, unsigned long arg)
{
	int __user * argp = (int __user *) arg;

	switch(cmd) {
         
		default :
			printk("Kernel: Inappropriate ioctl for cmd.\n");
			return -1;
	}
}

static struct file_operations vicap_fops = {
    .owner      = THIS_MODULE,
    .unlocked_ioctl = vicap_ioctl,
    .open       = vicap_open,
    .release    = vicap_close
};

static struct miscdevice vicap_dev = {
   .minor		= MISC_DYNAMIC_MINOR,
   .name		= DEV_NAME,
   .fops  		= &vicap_fops,
};

static int __init vicap_init(void)
{
	int reg = -1;

	base = ioremap_nocache((unsigned long VICAP_BASE, (unsigned long (VICAP_SIZE * VICAP_NUM));
	if (!base) {
		printk("Kernel: ioremap vicap base failed!\n");
		return -ENOMEM;
	}

	ret = misc_register(&vicap_dev);
	if (0 != ret) {
		printk("Kernel: register vicap device failed.\n");
		return -1;
	}

	test_read_default();
}

static void __exit vicap_exit(void)
{
	unsigned int num;

	iounmap((void *) base);
	misc_deregister(&vicap_dev);
}

module_init(vicap_init);
module_exit(vicap_exit);
MODULE_DESCRIPTION("vicap driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xiaozhi");
